home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #11 (Aug 86) / pascal / TML source / Sleuth.pas < prev    next >
Pascal/Delphi Source File  |  1986-07-16  |  19KB  |  682 lines

  1. program KeyboardSleuth;
  2.  
  3. {     Keyboard Sleuth: analyze key mappings
  4.        Stand-alone version written in Rascal
  5.        By Joel West, August 1986, for MacTutor
  6.     
  7.     ** Converted to TML Pascal by David E. Smith **
  8.     
  9.        Tries to figure out what keyboard is installed
  10.        Uses several approaches:
  11.         -Dump and analyze keyboard #
  12.         -Check keypad for Mac 512 vs. Mac Plus
  13.          -Look at INTL resources to find for country code
  14.         -Check for mapping of space key (US vs. Foreign)
  15.     Then allows user to type keys and shows their keycodes and ASCII values
  16.     Dumps all this to screen and to a logfile }
  17.  
  18. { Include files and constants }
  19.  
  20. {$I MemTypes.ipas  }
  21. {$I QuickDraw.ipas }
  22. {$I OSIntf.ipas    }
  23. {$I ToolIntf.ipas  }
  24. {$I PackIntf.ipas  }
  25. {$I HFS.ipas       }
  26.  
  27. { ---------------- GLOBAL CONSTANTS ------------ }    
  28. CONST
  29.     Key1Trans = $29E;          { Low Memory Globals }
  30.     Key2Trans = $2A2;
  31.     EOL = 13;                  { end of line file delimiter (RETURN) }
  32.     {menu res id's }
  33.     AppleMenu = 256;
  34.     FileMenu  = 257;
  35.     EditMenu  = 258;
  36.     
  37. { ---------------- ASCII values ------------ }
  38.     Space = $20;                {   }
  39.  
  40. { The following are Key #10, where US,UK "/" is (key # differs in US) }
  41.  
  42.     Slash = $2F;                { /    UK      }
  43.     Minus = $2D;                { -    German, Spanish, Swedish }
  44.     Equals = $3D;               { =    French  }
  45.     Ograve = $98;               { ò    Italian }
  46.     Eaigu = $8E;                { é    French Canadian }
  47.     
  48. { The following are Key # 36, where UK "`" (accent grave) is
  49.    Used only to distinguish Spanish from German and Swedish } 
  50.    
  51.     Degree = $A1;               { °    Spanish/Latin American }
  52.     Hash = $8A;                 { #    German   }
  53.     Apos = $27;                 { '    Swedish  }
  54.     
  55. { ---------------- Keycap Numbers ------------ }
  56.  
  57.     USspKey = 49;               { space bar in US }
  58.     UKspKey = 52;               { space bar in UK and other Euro-Classics}
  59.     UKslKey = 10;               { / key in UK }
  60.     UKgrKey = 36;               { ` (dead) key in UK }
  61.  
  62. { ---------------- GLOBAL VARIABLES ------------ }    
  63.  
  64. VAR
  65.     {my stuff}
  66.     mywindow:     WindowPtr;     { our window pointer }
  67.     finished:    Boolean;    {program terminator}
  68.     ClockCursor:CursHandle; {handle to the waiting watch cursor}    
  69.     {STDFile stuff}
  70.     logfile:     INTEGER;     { file status }          
  71.     logname:     STR255;        { file name }
  72.     volNumber:     INTEGER;      { vRefNum }
  73.     fileNumber:    INTEGER;     { file number }
  74.     {Screen stuff}
  75.     DragArea:   Rect;          {holds the area where window can be dragged in}
  76.     GrowArea:   Rect;          {holds the area to which a window's size can change}
  77.     Screen:     Rect;          {holds the screen dimensions }
  78.     {TextEdit stuff}
  79.     DestRect:    Rect;    
  80.     ViewRect:    Rect;
  81.     OKRect:        rect;    {don't invalidate this}
  82.     theText: TEHandle;
  83.     scrollflg:    Boolean;
  84.  
  85. { ---------------- BEGIN CODE ------------ }    
  86.  
  87. Function KeyTrans(keyno,modifies: Integer) : Integer;    EXTERNAL; 
  88. {$U keytrans    }
  89. { Translate key number and modifiers to 
  90.    their corresponding ASCII value  }
  91.  
  92. { This tries to call the country-specific keycode translator
  93.    that is loaded in location $29E.  It calls the keypad translator
  94.    at Key2Trans for keycodes >= 64.
  95.    
  96.    Both routines expect the keycode in register d2, and the modifiers
  97.    in the lower bits of register d1; they return an ASCII value in
  98.    register D0  } 
  99.  
  100. Function CR:str255;
  101.     begin
  102.         CR:= chr(EOL)
  103.     end;
  104.     
  105. PROCEDURE Openlog;
  106. { open keyboard logfile to save all messages for later review }
  107. label 1;
  108. Var     
  109.     where:        Point;
  110.     Prompt:       STR255;
  111.     origName:     STR255;
  112.     reply:        SFReply; { standard file reply record }
  113.     Info:        FInfo;   { Finder file info reply record }
  114.     vol:        INTEGER;  { vRefNum }
  115.     fileno:        INTEGER;  { file number }
  116.     resultCode:    OSErr;
  117.     
  118. Begin
  119.    where.v := 50;
  120.    where.h := 50;
  121.    Prompt := 'Save your log file as:';
  122.    origName := 'KeyBoard Log';
  123.    DILoad;    {in case disks are switched}
  124.    SFPutFile(Where, Prompt, origName, Nil, reply);
  125.    logname := reply.fName;
  126.    vol := reply.vRefNum;
  127.    IF reply.good = FALSE THEN 
  128.            logfile := 0     {bad file} 
  129.     ELSE 
  130.            logfile:= 1;    {good file}    
  131.     IF logfile = 0 THEN goto 1;
  132.     
  133.     resultCode:=GetFInfo (logname, vol, Info);
  134.     case resultCode of
  135.     
  136.         NoErr:  { file exists..delete it }
  137.         Begin
  138.             if Info.fdType <>'TEXT' then 
  139.             begin
  140.                 logfile:=0;
  141.                 goto 1;
  142.             end;
  143.             resultCode:=RstFlock(logname,vol);
  144.             if resultCode <> NoErr then 
  145.             begin
  146.                 logfile:=0;
  147.                 goto 1;
  148.             end;
  149.             resultCode:=FSDelete(logname,vol);
  150.             if resultCode <> NoErr then
  151.             begin
  152.                 logfile:=0;
  153.                 goto 1;
  154.             end;
  155.             resultCode:= Create (logname, vol, 'MACA', 'TEXT');
  156.             if resultCode <> NoErr then
  157.             begin
  158.                 logfile:=0;
  159.                 goto 1;
  160.             end;            
  161.         end;    
  162.         FNFErr:    { file not found so create one }
  163.         begin
  164.             resultCode:= Create (logname, vol, 'MACA', 'TEXT');
  165.             if resultCode <> NoErr then
  166.             begin
  167.                 logfile:=0;
  168.                 goto 1;
  169.             end;
  170.         end;            
  171.         OTHERWISE logfile:=0;
  172.     End; { case }
  173.     if logfile = 0 then goto 1;
  174.     
  175.     resultCode:= FSOpen (logname, vol,fileno);  { open log file }
  176.     if resultCode <> NoErr then
  177.         begin
  178.             logfile:=0;
  179.             goto 1;
  180.         end;
  181.     resultCode:= SetFPos (fileno, FSFromStart, 0);
  182.     if resultCode <> NoErr then
  183.         begin
  184.             logfile:=0;
  185.             goto 1
  186.         end;
  187.     volNumber:=vol;
  188.     fileNumber:=fileno;        
  189. 1:
  190.     if logfile = 1 then 
  191.         SetWTitle(mywindow, logname)
  192.     else 
  193.         SetWTitle(mywindow, 'No Log File!');
  194. End;
  195.  
  196. Procedure PutString(str: Str255);
  197. { Write a string to the log file and to the screen }
  198.  
  199. Var    
  200.     resultCode:    OSErr;
  201.     strlen:        LONGINT;
  202.     scrollup:    integer;
  203.     curlines:    integer;
  204.     linepos:    integer;
  205.     newpos:        integer;
  206.     endpos:        integer;
  207. BEGIN          
  208.   
  209.     strlen:=length(str);    
  210.     TEInsert(POINTER(ORD(@str)+1),strlen,theText);
  211.     TEIdle(theText);
  212.     
  213.     HLock(handle(theText));
  214.     IF (not scrollflg) then
  215.         begin            
  216.             scrollup:=theText^^.lineHeight;
  217.             curlines:=theText^^.nLines;
  218.             linepos:=curlines*scrollup;
  219.             endpos:=theText^^.ViewRect.bottom;    
  220.             if (linepos>=endpos) then 
  221.                 scrollflg:=true;                
  222.         end;
  223.     if scrollflg then TEScroll(0,-theText^^.lineHeight,theText);        
  224.     HUnlock(handle(theText));
  225.     
  226.     IF logfile = 1 THEN
  227.     Begin
  228.         resultCode:= FSWrite (fileNumber, strlen, POINTER(ORD(@str)+1));
  229.         if resultCode <> NoErr then logfile:=0;
  230.     End;
  231. END;
  232.  
  233. Function IntToString(num: Integer):str255;
  234. {integer to string}
  235. VAR
  236.     s: Str255;
  237.     longnum: LongInt;
  238. BEGIN
  239.       longnum:=num;
  240.     NumToString(longnum, s);
  241.     IntToString:=s;
  242. END;
  243.  
  244. Function KbdType: Integer;
  245. { Fetch low memory value at $21E, a byte, indicating the keyboard number }
  246. Type
  247.     magicHandle=^magicptr;
  248.     magicptr = ^magic;
  249.     magic = packed record
  250.         case boolean of
  251.            true:  (l: longint);
  252.            false: (byte3,byte2,byte1,byte0: Byte)
  253.         end;
  254. Var
  255.     tempHandle: Handle;          {handle signed byte}
  256.     magicman:    magicHandle;    {handle to magic}
  257.     addr:        INTEGER;
  258.     mysize:        INTEGER;
  259.     
  260. BEGIN          
  261.       addr:= $021E;
  262.     mysize:=SIZEOF(magicman);
  263.     tempHandle:=NewHandle(mysize);
  264.     magicman:=magicHandle(tempHandle);
  265.     magicman^:=pointer(addr);
  266.     KbdType:=magicman^^.byte3;
  267.     disposHandle(tempHandle);        
  268. END;
  269.  
  270. Procedure ShowIntlNation;
  271. { Show }
  272. VAR
  273.     country: integer;
  274.     ih: intl0Hndl;
  275.     s:str255;
  276.     known: Boolean;    
  277. BEGIN
  278.     ih := intl0Hndl(IUGetIntl(0));          { get INTL 0 resource }
  279.     country := (ih^^.intl0Vers) div 16;     { country is upper byte }
  280.     s:='This Mac is configured for ';
  281.     known:=true;    {be optomistic}
  282.         
  283. { There are a number of symbolic constants for these (verUS, verFrance, etc.),
  284.    but unless if you have the latest update to your development system, you
  285.    probably won't have all 26.  I've hard-coded them for clarity.   }
  286.    
  287.        CASE country OF
  288.            0:   s:=concat(s,'the US or Canada'); 
  289.            1:   s:=concat(s,'France'); 
  290.            2:   s:=concat(s,'U.K. or Ireland'); 
  291.            3:   s:=concat(s,'Deutschland');       { Germany }
  292.            4:   s:=concat(s,'Italia'); 
  293.            5:   s:=concat(s,'Nederland');         { Netherlands }
  294.            6:   s:=concat(s,'Belgique ou Luxembourg'); 
  295.            7:   s:=concat(s,'Sverige');           { Sweden }
  296.            8:   s:=concat(s,'Españá');            { Spain }
  297.            9:   s:=concat(s,'Danmark'); 
  298.           10:   s:=concat(s,'Portugal'); 
  299.           11:   s:=concat(s,'Quebec');            { French Canada }
  300.           12:   s:=concat(s,'Norge');             { Norway }
  301.           13:   s:=concat(s,'Yisra’el'); 
  302.           14:   s:=concat(s,'Nippon');            { Japan }
  303.           15:   s:=concat(s,'Australia or New Zealand'); 
  304.           16:   s:=concat(s,'Arabiyah'); 
  305.           17:   s:=concat(s,'Suomi');             { Finland }
  306.           18:   s:=concat(s,'Suisse');            { French Swiss }
  307.           19:   s:=concat(s,'Schweiz');           { German Swiss }
  308.           20:   s:=concat(s,'Ellas');             { Greece }
  309.           21:   s:=concat(s,'Island');            { Iceland }
  310.           22:   s:=concat(s,'Malta'); 
  311.           23:   s:=concat(s,'Kypros');            { Cyprus } 
  312.           24:   s:=concat(s,'Türkiye'); 
  313.           25:   s:=concat(s,'Jugoslavija');       
  314.         OTHERWISE
  315.             Begin
  316.                 known:=false;
  317.                 s:=concat(s,'an unknown country, #',IntToString(country),'. ');                
  318.             End;
  319.     END;  {case}    
  320.     if known then s:=concat(s,'. ');
  321.     s:=concat(s,CR,CR);
  322.     PutString(s);
  323. END;
  324.  
  325. Procedure ShowModel;
  326. { Guess which type of Macintosh keyboard }
  327.     
  328. Var
  329.     s,ss:str255;
  330.     Kbd:INTEGER;
  331.     
  332. BEGIN
  333. { Use derived keyboard numbers }
  334.     Kbd:=KbdType;
  335.     ss:=IntToString(Kbd);
  336.        s:=concat('The keyboard type is ',ss);
  337.     CASE Kbd OF
  338.         11: s:=concat(s,', which is a Mac Plus keyboard.');
  339.         3:    s:=concat(s,', which is the Classic Mac keyboard.');
  340.     OTHERWISE    s:=concat(s,', which is unknown.');
  341.     END;  {case}
  342.     s:=concat(s,CR);
  343.     PutString(s);
  344. END;
  345.  
  346. Procedure GuessKeyNation;
  347. { Guess which country keyboard mappings are set for  }
  348. Var
  349.     s: str255;
  350. BEGIN    {proc}
  351. { Try mapping of certain keys to figure US vs. non-US keyboard }
  352. IF (KeyTrans(USspKey,0) = Space) THEN
  353.     begin
  354.     s:='This is US, Canadian or down under.';
  355.     end    {IF..THEN}
  356. ELSE
  357. BEGIN
  358.     IF (KeyTrans(UKspKey,0) = Space) THEN
  359.         BEGIN
  360.         { Use UK "/" key to guess at nationality }
  361.         CASE KeyTrans(UKslKey,0) OF
  362.         Slash:              { /    UK      } 
  363.                s:=concat(s,'I am British or Dutch.');
  364.         Ograve:             { ò    Italian }
  365.                s:=concat(s,'Sono Italiano.');
  366.         Equals:             { =    French  }
  367.                s:=concat(s,'Je suis français, suisse ou belge.');
  368.         Eaigu:              { é    French Canadian }
  369.                s:=concat(s,'Je suis canadien.');
  370.         Minus:              { -    German, Spanish, Swedish  }
  371.                     
  372.             { Use UK accent grave (dead `) to tell 
  373.                 German, Spanish, and Swedish }
  374.                         
  375.                CASE KeyTrans(UKgrKey,0) OF
  376.                Hash:       { #    German   }
  377.                  s:=concat(s,'Ich bin ein Deutscher.');
  378.                Degree:     { ç    Spanish  }
  379.                  s:=concat(s,'Habla Español.');
  380.                Apos:       { '    Swedish   }
  381.                  s:=concat(s,'This is Swedish.');
  382.                OTHERWISE   { I have no country! }
  383.                  s:=concat(s,'¡No tengo un país!');
  384.                END; {case UKgrKey}
  385.            OTHERWISE
  386.             begin
  387.                 s:=concat(s,'I am a Mac without a country!');
  388.             end; {otherwise}
  389.         END;  {CASE}    
  390.           END    {IF...THEN}
  391.     ELSE
  392.         begin
  393.            s:=concat(s,'Neither US nor European, what is it?');
  394.         end;    {else}
  395. END;     {IF..THEN..ELSE}
  396. s:=concat(s,CR,CR,'Type keys, or click mouse to quit.',CR);
  397. PutString(s);
  398. END;    {proc}
  399.  
  400. Procedure DoMyStuff;
  401. Var
  402.     s: str255;    
  403. BEGIN 
  404.     OpenLog;              { log file }
  405.     ShowIntlNation;       { Find country code }
  406.     ShowModel;            { Examine keyboard type }
  407.     GuessKeyNation;       { Look at key mappings } 
  408.     showWindow(mywindow);    
  409. END; 
  410.  
  411. { ----- Following code is standard Mac Shell stolen from TML Examples ---}
  412.  
  413. PROCEDURE DoMenu(select:longint);
  414. Var    Menu_No:    integer;   {menu selected}
  415.       Item_No:    integer;   {item selected}
  416.       NameHolder: Str255;    {DA or Font name holder }
  417.       DNA:        integer;   {OpenDA result}    
  418. Begin
  419.    If select <> 0 then 
  420.    begin
  421.      Menu_No := HiWord(select);   {get the Hi word of...}
  422.      Item_no := LoWord(select);   {get the Lo word of...}     
  423.      Case Menu_No of     
  424.         AppleMenu: 
  425.             Begin
  426.               GetItem(GetMHandle(AppleMenu), Item_No, NameHolder);
  427.               DNA := OpenDeskAcc(NameHolder);
  428.             End; {applemenu}
  429.         FileMenu: Finished:=true;          {quit}
  430.         EditMenu: 
  431.             Begin
  432.             If Not SystemEdit(Item_no - 1) 
  433.             then
  434.               Case Item_No of
  435.                 1: begin end;           {undo}
  436.                   { 2:             line divider}
  437.                 3: TECut(theText);      {cut}
  438.                 4: TECopy(theText );    {copy}
  439.                 5: TEPaste(theText );   {paste}
  440.                 6: TEDelete(theText );  {clear}
  441.               End; {case}
  442.             End;  {editmenu}            
  443.         end; {case menu_no}    
  444.          HiliteMenu(0);     {unhilite after processing menu}
  445.        end; {If select <> 0}   
  446. End; {of DoMenu procedure}
  447.  
  448. PROCEDURE doMouseDowns(Event:EventRecord);
  449. Var     Location        :integer;
  450.         WindowPointedTo    :WindowPtr;
  451.         MouseLoc        :Point;
  452.         WindoLoc        :integer;
  453. Begin
  454.    MouseLoc := Event.Where;
  455.    WindoLoc := FindWindow(MouseLoc, WindowPointedTo);
  456.    Case WindoLoc of 
  457.       inMenuBar:       DoMenu(MenuSelect(MouseLoc)); 
  458.       inSysWindow:     SystemClick(Event,WindowPointedTo); 
  459.       inContent:
  460.               if WindowPointedto <> FrontWindow then 
  461.               SelectWindow(WindowPointedTo);              
  462.       inGrow:        Begin End; {no grow}                
  463.       inDrag:          DragWindow(WindowPointedTo,MouseLoc,DragArea); 
  464.       inGoAway:
  465.           Begin
  466.               If TrackGoAway(WindowPointedTo,MouseLoc) then 
  467.             Begin                
  468.                 DisposeWindow(WindowPointedTo);
  469.                 finished:=true;
  470.             End;
  471.         End; {inGoAway}
  472.    End{ of case};
  473. End;
  474.  
  475. PROCEDURE doKeyDowns(Event:EventRecord);
  476.  
  477. Type
  478.     magicHandle=^magicptr;
  479.     magicptr = ^magic;
  480.     magic = packed record
  481.         case boolean of
  482.            true:  (l: longint);
  483.            false: (byte3,byte2,byte1:Byte;chr0: Char)
  484.         end;
  485.  
  486. Var CharCode:      char;
  487.     keycode:    Byte;
  488.     mods:        INTEGER;
  489.     s:            str255;
  490.     keyc:        INTEGER;
  491.     asc:        INTEGER;    
  492.     tempHandle: Handle;          {handle to signed byte}
  493.     magicman:    magicHandle;    {handle to magic}
  494.     mysize:        INTEGER;        
  495. Begin        
  496.     mysize:=SIZEOF(magicman);
  497.     tempHandle    :=NewHandle(mysize);
  498.     magicman    :=magicHandle(tempHandle);        
  499.     magicman^^.l:=Event.message;
  500.     CharCode    :=magicman^^.chr0;
  501.     keycode        :=magicman^^.byte1;
  502.     keyc        := keycode;        
  503.     mods        := Event.modifiers;    
  504.     s:=concat('Key #',IntToString(keyc));    
  505.     IF BitAnd(mods,optionKey) = optionKey THEN        
  506.             s:=concat(s,' with Option');        
  507.     IF BitAnd(mods,shiftKey) = shiftKey THEN            
  508.             s:=concat(s,', shifted');        
  509.     IF BitAnd(mods,alphaLock) = alphaLock THEN
  510.             s:=concat(s,', Caps Locked');            
  511.     asc := KeyTrans(keyc,mods);     { translate to ASCII }
  512.     { Don't want to print control characters }
  513.     IF asc >= 32 THEN
  514.         BEGIN                
  515.         s:=concat(s,' is ',chr(asc),' (ascii ',IntToString(asc),').');            
  516.         END;
  517.     s:=concat(s,CR);
  518.     PutString(s)             
  519. END;
  520.                   
  521. PROCEDURE doActivates(Event: EventRecord);
  522. Var     TargetWindow:WindowPtr;
  523. Begin
  524.    TargetWindow := pointer(ord4(Event.message));
  525.    If Odd(Event.modifiers) then
  526.            Begin    {activate}
  527.                SetPort(TargetWindow);
  528.            End
  529.    else            {deactivate} 
  530.            Begin End;
  531. End;
  532.  
  533. PROCEDURE doUpdates(Event:EventRecord);
  534. Var     
  535.     UpDateWindow,TempPort: WindowPtr;
  536. Begin
  537.    UpDateWindow := pointer(ord4(Event.message)); {typecasting}
  538.    if UpDateWindow = mywindow then
  539.    Begin
  540.    
  541.            GetPort(TempPort);      {Save the current port}
  542.            SetPort(mywindow);      {set the port to one in Evt.msg}
  543.            BeginUpDate(mywindow);
  544.                EraseRect(mywindow^.visRgn^^.rgnBBox);
  545.             TEUpdate(mywindow^.visRgn^^.rgnBBox,theText);    {update window contents}
  546.            EndUpDate(mywindow);
  547.            SetPort(TempPort);       {restore to the previous port}
  548.     End;
  549. End;
  550.  
  551. PROCEDURE EndProgram;     
  552. Var
  553.      resultcode:    OSErr;    
  554. Begin
  555.     IF logfile =1 THEN
  556.     begin
  557.         resultCode:= FSClose(fileNumber);
  558.     end;
  559.     ExitToShell;
  560. End;
  561.  
  562. PROCEDURE MainEventLoop;
  563. Var     Event:EventRecord;
  564.         DoIt: Boolean;        
  565. Begin
  566.     InitCursor;
  567.        Repeat                    
  568.           SystemTask;      {support DAs}  
  569.           DoIt := GetNextEvent(EveryEvent,Event);
  570.           If DoIt{is true} then {we'll DoIt}
  571.     Case Event.what of
  572.            mouseDown      : doMouseDowns(Event);     {1}
  573.         mouseUp        : begin end;            {2}
  574.            KeyDown        : doKeyDowns  (Event);    {3}
  575.         keyUp        : begin end;            {4}
  576.         autoKey        : begin end;            {5}
  577.         updateEvt      : doUpdates   (Event);    {6}
  578.         diskEvt        : begin end;            {7}
  579.            activateEvt    : doActivates (Event);    {8}
  580.         {abort evt now reserved for future}    {9}
  581.            networkEvt    : begin end;            {A}
  582.         driverEvt    : begin end;            {B}
  583.         app1Evt        : begin end;            {C}
  584.         app2Evt        : begin end;            {D}
  585.         app3Evt        : begin end;            {E}
  586.         app4Evt        : begin end;            {F}        
  587.     End;{of Case}
  588.     Until Finished; {end program}
  589.            EndProgram;
  590. End;
  591.  
  592. PROCEDURE InitThings;
  593. Begin
  594.    InitGraf(@thePort);                
  595.    ClockCursor := GetCursor(watchCursor);
  596.    HLock(Handle(ClockCursor));
  597.    SetCursor(ClockCursor^^);   
  598.    InitFonts;                     
  599.    InitWindows;                   
  600.    InitMenus;                     
  601.    TEInit;                        
  602.    InitDialogs(Nil);              
  603.    FlushEvents(everyEvent,0);
  604.    scrollflg:=false;    {too early to scroll!}
  605.    finished:=false;    {clear program terminator}   
  606. End;
  607.  
  608. PROCEDURE SetupLimits;
  609. Begin
  610.    Screen := ScreenBits.Bounds;   {set screen 512 by 342 pixels}
  611.    SetRect(DragArea,Screen.left+4,Screen.top+24,Screen.right-4,Screen.bottom-4);
  612.    SetRect(GrowArea,Screen.left,Screen.top+24,Screen.right,Screen.bottom);   
  613. End;
  614.  
  615. Procedure SetupWindows;
  616.  
  617. Const
  618.     sbarwidth=16;
  619.  
  620. Var    myrect:      Rect;
  621.     windtype: integer;
  622.     Visible:  boolean;
  623.     GoAway:   boolean;
  624.     RefVal:   LongInt;
  625.     
  626. Begin
  627.    
  628.    SetRect(myrect,10,40,500,330); {set the size of the window -global coordinates}
  629.    windtype := 4;                 {set window type - nogrowdocproc   }
  630.    Visible := false;              {set the window to invisible }
  631.    GoAway := true;                {give the window a GoAway box }
  632.  
  633.    mywindow:= NewWindow(Nil,    { Window Mgr will allocate space in Heap}
  634.               myrect,            { rectangle with windows size}
  635.               'Keyboard Sleuth',{ the title of the window }
  636.               Visible,           { set the window to invisible }
  637.               windtype,          { Window definition ID}
  638.               POINTER(-1),      { behind ptr: window is set to front}
  639.               GoAway,            { draw a goaway region in title area }
  640.               RefVal);           { 32-bit value that can be used by App}
  641.         
  642.        SetPort(mywindow);
  643.     TextFont(Geneva);
  644.  
  645. { Set Up Text Edit Record for this Window }
  646.  
  647. with myWindow^.portRect do
  648.     SetRect(ViewRect,4,4,right-(sbarwidth-1),bottom-(sbarwidth-1));
  649. DestRect:=ViewRect;
  650. theText:= TENew(DestRect,ViewRect)
  651.  
  652.    
  653.    {NOTE: NewWindow have initiated an ActivatEvt and an }
  654.    {      UpDateEvt event. They are being queued up by the event manager.}
  655.    {      Also, the window record is Non-relocatable, so put it on the stack}
  656.    {      or create it so that it is low in the heap space, reduce fragmentation}
  657. End;    
  658.     
  659. PROCEDURE SetupMenus;
  660. Var     myMenu        :MenuHandle;
  661.       NameHolder    :STR255;               
  662. Begin
  663.    myMenu := GetMenu(AppleMenu);{from resource file}
  664.    AddResMenu(myMenu,'DRVR');   {adds DAs}
  665.    InsertMenu(myMenu,0);        {put list in menu} 
  666.    myMenu := GetMenu(FileMenu); {Quiting...}
  667.    InsertMenu(myMenu,0); 
  668.    myMenu := GetMenu(EditMenu); {DA support...}
  669.    InsertMenu(myMenu,0); 
  670.    DrawMenuBar;                   {show the menu bar}
  671. End;
  672.  
  673. { ---------------- MAIN PROGRAM ------------ }
  674.  
  675. BEGIN
  676.    InitThings;
  677.    SetupLimits;
  678.    SetupWindows;  {do first so its low in heap}
  679.    SetupMenus;   
  680.    DoMyStuff;
  681.    MainEventLoop;
  682. END.